package com.cpd.blog.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cpd.blog.common.constant.Constant;
import com.cpd.blog.common.constant.RedisKey;
import com.cpd.blog.common.constant.StatusCode;
import com.cpd.blog.common.utils.*;
import com.cpd.blog.dto.Result;
import com.cpd.blog.dto.User.UserCardRep;
import com.cpd.blog.dto.User.UserVo;
import com.cpd.blog.entity.User;
import com.cpd.blog.manager.manager.UserManager;
import com.cpd.blog.manager.mapper.UserMapper;
import com.cpd.blog.service.LoginService;
import com.cpd.blog.service.UserService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Copydown
 * @date 2021/8/16 14:53
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;

    private final RedisUtil redisUtil;

    private final EmailUtil emailUtil;

    @Lazy
    @Autowired
    private LoginService loginService;

    private final UserManager userManager;

    @Value("${mock.email.isSend}")
    private Boolean isSend;

    @Override
    public UserVo findUserVoById(Long id) {
        User user = userMapper.selectById(id);
        return VoUtil.toVo(user);
    }

    @Override
    public String updateUserLogin(User user) {

        String token = JWTUtils.createToken(user.getId());
        UserVo userVo = VoUtil.toVo(userManager.updateUserLogin(user, token));

        redisUtil.set(RedisKey.TOKEN + token, JSON.toJSONString(userVo), Constant.ONE_INT, TimeUnit.DAYS);
        return token;
    }

    @Override
    public User findUserById(Long id) {
        return userMapper.selectById(id);
    }

    @Override
    public boolean checkUserPwd(User user, String password) {

        String pwd = DigestUtils.md5Hex(password + user.getSalt());

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(User::getId, user.getId())
                .eq(User::getAccount, user.getAccount())
                .eq(User::getPassword, pwd);

        return CheckUtil.isNotNull(userMapper.selectOne(queryWrapper));
    }

    @Override
    public Result findUserByToken(String token) {
        UserVo userVo = checkToken(token);
        if (userVo == null) {
            return Result.fail(StatusCode.TOKEN_ERROR);
        }
        return Result.success(userVo);
    }

    @Override
    public User findUserByAccount(String account) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(User::getAccount, account).last("limit 1");
        return userMapper.selectOne(queryWrapper);
    }

    @Override
    public void save(User user) {
        //保存用户时 id会自动生成（分布式id，采用雪花算法 ->User）
        userMapper.insert(user);
    }

    @Override
    public UserVo getUserVoByToken(String token) {
        return checkToken(token);
    }


    @Override
    public UserVo checkToken(String token) {
        if (JWTUtils.checkTokenNotBlank(token)) {
            return redisUtil.checkAndGetObj(RedisKey.TOKEN + token, UserVo.class);
        }
        return null;
    }

    @Override
    public Result editNickName(String name) {

        List<User> userList = userManager.findUserListByNickName(name);
        if (userList.size() >= 1) {
            return Result.fail(StatusCode.USER_NICKNAME_EXIST);
        }
        if (userManager.changeUserNickName(name)) {
            String token = RedisKey.TOKEN + redisUtil.compareHashAndGet(RedisKey.IS_LOGIN, CurrentUser.getId());
            UserVo userVo = redisUtil.checkAndGetObj(token, UserVo.class);
            userVo.setNickname(name);
            Boolean isUpdate = redisUtil.setIfPresent(token, JSON.toJSONString(userVo));
            if (isUpdate) {
                // TODO
            }
            return Result.success(StatusCode.SUCCESS);
        }
        return Result.fail(StatusCode.USER_CHANGE_NICKNAME_FAILED);
    }

    @Override
    public Result mineCard(String token) {
        UserVo userVo = checkToken(token);

        Long authorId = Long.parseLong(userVo.getId());
        Long viewCount = userManager.calViewCountsById(authorId);
        Long articleCount = userManager.countArticleById(authorId);

        UserCardRep userCardRep = new UserCardRep();
        userCardRep.setViewCount(viewCount);
        userCardRep.setArticleNum(articleCount);
        userCardRep.setAvatar(userVo.getAvatar());
        userCardRep.setNickName(userVo.getNickname());

        return Result.success(userCardRep);
    }

    @Override
    public Result editPassword(String password, String emailCode) {

        if (CheckUtil.hasBlank(password,emailCode)) {
            return Result.fail(StatusCode.PARAMS_NULL);
        }

        String key = RedisKey.EMAIL_PWD_CODE + CurrentUser.getId();
        String code = redisUtil.get(key);

        if (CheckUtil.isBlank(code)) {
            return Result.fail(StatusCode.VERIFY_CODE_EXPIRE);
        }
        if (CheckUtil.isNotEquals(emailCode, code)) {
            return Result.fail(StatusCode.VERIFY_CODE_WRONG);
        }

        Result result = userManager.changePassword(password);
        if (CheckUtil.isNotEquals(result.getCode(), StatusCode.SUCCESS.getCode())) {
            return result;
        }
        redisUtil.delete(key);
        return Result.success();
    }

    @Override
    public Result sendEmail() {
        return emailUtil.sendEmailSmsCode(isSend);
    }
}
